﻿Imports System.Security.Cryptography
Imports System.Text
Imports System.IO

Public Class clsEncryptString
    Public Const mscSession As String = "Setting"
    Public Const mscStartDate As String = "InitValue"
    Public Const mscNumberDate As Integer = 90
    Public Const mscLastAccess As String = "LastValue"
    Public Const mscDateFormat As String = "{0}/{1}/{2}/{3}/{4}"

    Private Shared _idKey As String

    Public Shared Property IDKey() As String
        Get
            Return _idKey
        End Get
        Set(ByVal value As String)
            _idKey = value
        End Set
    End Property

    ''' <summary>
    ''' Tao Key Ma hoa
    ''' </summary>
    ''' <param name="strPassword"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CreateKey(ByVal strPassword As String) As Byte()
        'Convert strPassword to an array and store in chrData.

        Dim chrData() As Char = strPassword.ToCharArray
        'Use intLength to get strPassword size.

        Dim intLength As Integer = chrData.GetUpperBound(0)
        'Declare bytDataToHash and make it the same size as chrData.

        Dim bytDataToHash(intLength) As Byte

        'Use For Next to convert and store chrData into bytDataToHash.

        For i As Integer = 0 To chrData.GetUpperBound(0)
            bytDataToHash(i) = CByte(Asc(chrData(i)))
        Next

        'Declare what hash to use.

        Dim SHA512 As New SHA512Managed
        'Declare bytResult, Hash bytDataToHash and store it in bytResult.

        Dim bytResult As Byte() = SHA512.ComputeHash(bytDataToHash)
        'Declare bytKey(31).  It will hold 256 bits.

        Dim bytKey(31) As Byte

        'Use For Next to put a specific size (256 bits) of 

        'bytResult into bytKey. The 0 To 31 will put the first 256 bits

        'of 512 bits into bytKey.

        For i As Integer = 0 To 31
            bytKey(i) = bytResult(i)
        Next

        Return bytKey
        'Return the key.
    End Function

    Public Shared Function CreateIV(ByVal strPassword As String) As Byte()
        'Convert strPassword to an array and store in chrData.

        Dim chrData() As Char = strPassword.ToCharArray
        'Use intLength to get strPassword size.

        Dim intLength As Integer = chrData.GetUpperBound(0)
        'Declare bytDataToHash and make it the same size as chrData.

        Dim bytDataToHash(intLength) As Byte

        'Use For Next to convert and store chrData into bytDataToHash.

        For i As Integer = 0 To chrData.GetUpperBound(0)
            bytDataToHash(i) = CByte(Asc(chrData(i)))
        Next

        'Declare what hash to use.

        Dim SHA512 As New SHA512Managed
        'Declare bytResult, Hash bytDataToHash and store it in bytResult.

        Dim bytResult As Byte() = SHA512.ComputeHash(bytDataToHash)
        'Declare bytIV(15).  It will hold 128 bits.

        Dim bytIV(15) As Byte

        'Use For Next to put a specific size (128 bits) of bytResult into bytIV.

        'The 0 To 30 for bytKey used the first 256 bits of the hashed password.

        'The 32 To 47 will put the next 128 bits into bytIV.

        For i As Integer = 32 To 47
            bytIV(i - 32) = bytResult(i)
        Next

        Return bytIV
        'Return the IV.
    End Function

    Public Shared Function EncryptData(ByVal strInputData As String, _
                                       ByVal bytKey() As Byte, _
                                       ByVal bytIV() As Byte) As String

        'Declare variables for encrypt/decrypt process.

        'Dim bytBuffer(4096) As Byte 'holds a block of bytes for processing
        Dim arrByteData As Byte() = UTF8Encoding.UTF8.GetBytes(strInputData)
        Dim oMemoryStream As New MemoryStream()
        Dim oEncryptData As Byte() = Nothing
        Dim csCryptoStream As CryptoStream
        'Declare your CryptoServiceProvider.

        Dim cspRijndael As New RijndaelManaged
        'Setup Progress Bar

        csCryptoStream = New CryptoStream(oMemoryStream, _
                                          cspRijndael.CreateEncryptor(bytKey, bytIV), _
                                          CryptoStreamMode.Write)
        'Determine if ecryption or decryption and setup CryptoStream.
        csCryptoStream.Write(arrByteData, 0, arrByteData.Length)
        csCryptoStream.FlushFinalBlock()
        'Use While to loop until all of the file is processed.
        oEncryptData = oMemoryStream.ToArray
        'Close FileStreams and CryptoStream.

        csCryptoStream.Close()
        oMemoryStream.Close()
        Return Convert.ToBase64String(oEncryptData)
    End Function

    Public Shared Function DecryptData(ByVal strInputData As String, _
                                       ByVal bytKey() As Byte, _
                                       ByVal bytIV() As Byte) As String

        'Declare variables for encrypt/decrypt process.

        'Dim bytBuffer(4096) As Byte 'holds a block of bytes for processing
        Dim arrByteData As Byte() = Convert.FromBase64String(strInputData)
        Dim oMemoryStream As New MemoryStream()
        Dim oEncryptData As Byte() = Nothing
        Dim csCryptoStream As CryptoStream
        'Declare your CryptoServiceProvider.

        Dim cspRijndael As New RijndaelManaged
        'Setup Progress Bar

        csCryptoStream = New CryptoStream(oMemoryStream, _
                                          cspRijndael.CreateDecryptor(bytKey, bytIV), _
                                          CryptoStreamMode.Write)
        'Determine if ecryption or decryption and setup CryptoStream.
        csCryptoStream.Write(arrByteData, 0, arrByteData.Length)
        csCryptoStream.FlushFinalBlock()
        'Use While to loop until all of the file is processed.
        oEncryptData = oMemoryStream.ToArray
        'Close FileStreams and CryptoStream.

        csCryptoStream.Close()
        oMemoryStream.Close()
        Return UTF8Encoding.UTF8.GetString(oEncryptData)
    End Function

    Public Shared Function SaveFirstDate(ByVal stringProduct As String) As Boolean
        Dim oStartString As String = GetSetting(stringProduct, mscSession, mscStartDate)
        If oStartString Is Nothing OrElse oStartString = "" Then
            Dim oNow As Date = Date.Now
            Dim strDate As String = String.Format(mscDateFormat, oNow.Day, oNow.Month, oNow.Year, oNow.Hour, oNow.Minute)

            strDate = EncryptData(strDate, CreateKey(My.Resources.PasswordKey), CreateIV(My.Resources.PasswordKey))
            SaveSetting(stringProduct, mscSession, mscStartDate, strDate)
            Return True
        End If
        Return False
    End Function

    Public Shared Sub SaveLastDate(ByVal stringProduct As String)
        Dim strStart As String = GetSetting(stringProduct, mscSession, mscStartDate)
        Dim oEndtString As String = GetSetting(stringProduct, mscSession, mscLastAccess)
        Dim oNow As Date = Date.Now
        Dim strDate As String = String.Format(mscDateFormat, oNow.Day, oNow.Month, oNow.Year, oNow.Hour, oNow.Minute)

        If oEndtString IsNot Nothing AndAlso oEndtString <> "" Then
            oEndtString = DecryptData(oEndtString, CreateKey(strStart), CreateIV(strStart))
            Dim strDateInfo As String() = oEndtString.Split("/")
            Dim oEndDate As Date = New Date(strDateInfo(2), strDateInfo(1), strDateInfo(0), strDateInfo(3), _
                                            strDateInfo(4), 0)
            If oNow <= oEndDate Then
                Exit Sub
            End If
        End If

        strDate = EncryptData(strDate, CreateKey(strStart), CreateIV(strStart))
        SaveSetting(stringProduct, mscSession, mscLastAccess, strDate)
    End Sub

    Public Shared Function CheckDayExpired(ByVal stringProduct As String) As Integer

        Dim oStartString As String = GetSetting(stringProduct, mscSession, mscStartDate)
        Dim oEndtString As String = GetSetting(stringProduct, mscSession, mscLastAccess)
        Dim oNow As Date = Date.Now
        Try
            oEndtString = DecryptData(oEndtString, CreateKey(oStartString), CreateIV(oStartString))
            oStartString = DecryptData(oStartString, CreateKey(My.Resources.PasswordKey), _
                                       CreateIV(My.Resources.PasswordKey))
            Dim strDateInfo As String() = oStartString.Split("/")
            Dim strEndDateInfo As String() = oEndtString.Split("/")
            Dim oEndDate As Date = New Date(strEndDateInfo(2), strEndDateInfo(1), strEndDateInfo(0), strEndDateInfo(3), _
                                            strEndDateInfo(4), 0)
            Dim oStartDate As Date = New Date(strDateInfo(2), strDateInfo(1), strDateInfo(0), strDateInfo(3), _
                                              strDateInfo(4), 0)

            If oEndDate > oNow Then
                Return - 2
            End If

            If (oNow - oStartDate).TotalDays > mscNumberDate Then
                Return - 1
            Else
                Return CInt(mscNumberDate - (oNow - oStartDate).TotalDays)
            End If
        Catch ex As Exception
            Throw
        End Try
    End Function

#Region "RegLicense"

    Public Shared Function InverseByBase(ByVal st As String, ByVal MoveBase As Integer) As String
        Dim SB As New StringBuilder()
        'st = ConvertToLetterDigit(st);
        Dim c As Integer
        Dim i As Integer = 0
        While i < st.Length
            If i + MoveBase > st.Length - 1 Then
                c = st.Length - i
            Else
                c = MoveBase
            End If
            SB.Append(InverseString(st.Substring(i, c)))
            i += MoveBase
        End While
        Return SB.ToString()
    End Function

    Public Shared Function InverseString(ByVal st As String) As String
        Dim SB As New StringBuilder()
        For i As Integer = st.Length - 1 To 0 Step - 1
            SB.Append(st(i))
        Next
        Return SB.ToString()
    End Function

    Public Shared Function ConvertToLetterDigit(ByVal st As String) As String
        Dim SB As New StringBuilder()
        For Each ch As Char In st
            If Char.IsLetterOrDigit(ch) = False Then
                SB.Append(Convert.ToInt16(ch).ToString())
            Else
                SB.Append(ch)
            End If
        Next
        Return SB.ToString()
    End Function

    ''' <summary>
    ''' moving all characters in string insert then into new index
    ''' </summary>
    ''' <param name="st">string to moving characters</param>
    ''' <returns>moved characters string</returns>
    Public Shared Function Boring(ByVal st As String) As String
        Dim NewPlace As Integer
        Dim ch As Char
        For i As Integer = 0 To st.Length - 1
            NewPlace = i*Convert.ToUInt16(st(i))
            NewPlace = NewPlace Mod st.Length
            ch = st(i)
            st = st.Remove(i, 1)
            st = st.Insert(NewPlace, ch.ToString())
        Next
        Return st
    End Function

    Public Shared Function MakePassword(ByVal st As String) As String
        If IDKey.Length <> 3 Then
            Throw New ArgumentException("IDKey must be 3 character length")
        End If

        Dim num As Integer() = New Integer(2) {}
        num(0) = Convert.ToInt32(IDKey(0).ToString(), 10)
        num(1) = Convert.ToInt32(IDKey(1).ToString(), 10)
        num(2) = Convert.ToInt32(IDKey(2).ToString(), 10)
        st = Boring(st)
        st = InverseByBase(st, num(0))
        st = InverseByBase(st, num(1))
        st = InverseByBase(st, num(2))

        Dim SB As New StringBuilder()
        For Each ch As Char In st
            SB.Append(ChangeChar(ch, num))
        Next
        Return SB.ToString()
    End Function

    Public Shared Function MakeSystemString(ByVal st As String) As String
        Return Boring(InverseByBase(SystemInfo.GetSystemInfo(st), 10))
    End Function

    Private Shared Function ChangeChar(ByVal ch As Char, ByVal EnCode As Integer()) As Char
        ch = Char.ToUpper(ch)
        If ch >= "A"c AndAlso ch <= "H"c Then
            Return Convert.ToChar(Convert.ToInt16(ch) + 2*EnCode(0))
        ElseIf ch >= "I"c AndAlso ch <= "P"c Then
            Return Convert.ToChar(Convert.ToInt16(ch) - EnCode(2))
        ElseIf ch >= "Q"c AndAlso ch <= "Z"c Then
            Return Convert.ToChar(Convert.ToInt16(ch) - EnCode(1))
        ElseIf ch >= "0"c AndAlso ch <= "4"c Then
            Return Convert.ToChar(Convert.ToInt16(ch) + 5)
        ElseIf ch >= "5"c AndAlso ch <= "9"c Then
            Return Convert.ToChar(Convert.ToInt16(ch) - 5)
        Else
            Return "0"c
        End If
    End Function

#End Region
End Class
